﻿using System.Collections.Concurrent;
using AutoTask.Collect;
using AutoTask.Model;
using AutoTask.Service.AutoTask;
using RpcClient.Interface;
using RpcHelper;

namespace AutoTask.Service
{
    [RpcClient.Attr.ClassLifetimeAttr(RpcClient.Attr.ClassLifetimeType.单例)]
    internal class TaskService : ITaskService
    {
        private readonly ConcurrentDictionary<Guid, SingleTask> _TaskList = new ConcurrentDictionary<Guid, SingleTask>();
        private Guid[] _Keys;
        private Timer _Timer;
        private Timer _ExecTimer;
        private readonly IUnityCollect _Unity;

        public TaskService(IUnityCollect unity)
        {
            _Unity = unity;
        }

        private void _Load(object state)
        {
            BasicTask[] tasks = _Unity.Resolve<IAutoTaskCollect>().GetTasks(RpcClient.RpcClient.CurrentSource.RegionId);
            if (tasks.IsNull())
            {
                return;
            }
            tasks = tasks.OrderBy(a => a.TaskPriority).ToArray();
            this._ClearTask(tasks);
            tasks.ForEach(a =>
            {
                if (!this._TaskList.TryGetValue(a.Id, out SingleTask task))
                {
                    _LoadTask(a);
                }
                else if (task.VerNum != a.VerNum)
                {
                    task.Reset(a.VerNum);
                }
            });
            this._Keys = this._TaskList.Keys.ToArray();
        }

        public void Init()
        {
            if (!_Unity.IsRegistered(typeof(IAutoTaskCollect)))
            {
                RpcClient.RpcClient.Load("AutoTask.Collect");
            }
            this._Timer = new Timer(new TimerCallback(this._Load), null, 100, 6000);
            this._ExecTimer = new Timer(new TimerCallback(this._ExecTask), null, 6000, 6000);
        }
        private void _ExecTask(object state)
        {
            if (this._Keys.IsNull())
            {
                return;
            }
            int time = HeartbeatTimeHelper.HeartbeatTime;
            this._Keys.ForEachByParallel(a =>
            {
                if (this._TaskList.TryGetValue(a, out SingleTask task))
                {
                    task.ExecTask(time);
                }
            });
        }
        private void _LoadTask(BasicTask obj)
        {
            SingleTask task = new SingleTask(obj.Id, obj.VerNum);
            if (task.Init())
            {
                this._TaskList.TryAdd(obj.Id, task);
            }
        }
        private void _ClearTask(BasicTask[] tasks)
        {
            if (this._TaskList.Count == 0)
            {
                return;
            }
            Guid[] removeId = this._Keys.Remove(tasks, (a, b) => a == b.Id);
            this._StopTask(removeId);
        }
        private void _StopTask(Guid[] removeId)
        {
            if (removeId.Length > 0)
            {
                removeId.ForEach(a =>
                {
                    if (this._TaskList.TryRemove(a, out SingleTask task))
                    {
                        task.StopTask();
                    }
                });
            }
        }

        public void Dispose()
        {
            _Timer.Dispose();
            _ExecTimer.Dispose();
        }
    }
}
